<template>
  <div class="video-upload-container">
    <div class="upload-card">
      <h2 class="upload-title">视频上传</h2>

      <form @submit.prevent="handleSubmit" class="upload-form">
        <!-- 视频文件上传 -->
        <div class="form-group">
          <label for="videoFile" class="form-label">选择视频文件 *</label>
          <div class="file-upload-area" @click="triggerFileInput" :class="{ 'has-file': videoFile }">
            <input
                id="videoFile"
                ref="videoFileInput"
                type="file"
                accept="video/*" extractFrames
                @change="handleVideoFileChange"
                class="file-input-hidden"
                required
            />
            <div v-if="!videoFile" class="upload-placeholder">
              <div class="upload-icon">📹</div>
              <div class="upload-text">点击选择视频文件</div>
              <div class="upload-hint">支持 MP4, AVI, MOV 等格式</div>
            </div>
            <div v-else class="file-info">
              <div class="file-icon">✅</div>
              <div class="file-details">
                <div class="file-name">{{ videoFile.name }}</div>
                <div class="file-size">{{ formatFileSize(videoFile.size) }}</div>
                <div v-if="videoInfo.duration" class="file-info-grid">
                  <div class="file-duration">时长: {{ formatDuration(videoInfo.duration) }}</div>
                  <div class="file-resolution">分辨率: {{ videoInfo.width }}x{{ videoInfo.height }}</div>
                  <div v-if="videoInfo.fps" class="file-fps">帧率: {{ videoInfo.fps.toFixed(1) }}fps</div>
                  <div v-if="videoInfo.format" class="file-format">格式: {{ videoInfo.format }}</div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 处理方式选择 -->
        <div v-if="!isProcessing && !extractedFrames.length" class="form-group">
          <label class="form-label">视频处理方式</label>
          <div class="processing-method-selector">
            <div
                class="method-option"
                :class="{ 'selected': processingMethod === 'html5' }"
                @click="processingMethod = 'html5'"
            >
              <div class="method-icon">⚡</div>
              <div class="method-info">
                <div class="method-name">HTML5 (快速)</div>
                <div class="method-desc">浏览器原生，无需下载</div>
              </div>
            </div>
            <div
                class="method-option"
                :class="{ 'selected': processingMethod === 'ffmpeg' }"
                @click="processingMethod = 'ffmpeg'"
            >
              <div class="method-icon">🎬</div>
              <div class="method-info">
                <div class="method-name">FFmpeg (推荐)</div>
                <div class="method-desc">专业级处理，支持更多格式</div>
              </div>
            </div>

          </div>
        </div>

        <!-- 帧选择区域 -->
        <div v-if="extractedFrames.length > 0" class="form-group">
          <label class="form-label">选择缩略图</label>
          <div class="frames-container">
            <div
                v-for="(frame, index) in extractedFrames"
                :key="index"
                class="frame-item"
                :class="{ 'selected': selectedFrameIndex === index }"
                @click="selectFrame(index)"
            >
              <img :src="frame" :alt="`帧 ${index + 1}`" class="frame-image"/>
              <div class="frame-overlay">
                <div class="frame-number">{{ index + 1 }}</div>
              </div>
            </div>
          </div>
          <div class="frame-hint">点击选择一张图片作为视频缩略图</div>
        </div>

        <!-- 视频标题 -->
        <div class="form-group">
          <label for="title" class="form-label">视频标题 *</label>
          <input
              id="title"
              v-model="formData.title"
              type="text"
              class="form-input"
              placeholder="将从视频文件名自动生成"
              required
          />
        </div>

        <!-- 视频描述 -->
        <div class="form-group">
          <label for="description" class="form-label">视频描述 *</label>
          <textarea
              id="description"
              v-model="formData.description"
              class="form-textarea"
              placeholder="请输入视频描述"
              rows="4"
              required
          ></textarea>
        </div>

        <!-- 视频时长（自动填充，只读） -->
        <div class="form-group">
          <label for="duration" class="form-label">视频时长 (秒)</label>
          <input
              id="duration"
              v-model.number="formData.duration"
              type="number"
              class="form-input"
              placeholder="将自动从视频解析"
              readonly
          />
          <div class="form-hint">时长将在选择视频后自动获取</div>
        </div>

        <!-- 演员选择 -->
        <div class="form-group">
          <label for="actor" class="form-label">选择演员 *</label>
          <select
              id="actor"
              v-model="formData.actorId"
              class="form-select"
              required
          >
            <option value="">请选择演员</option>
            <option
                v-for="actor in actors"
                :key="actor.id"
                :value="actor.id"
            >
              {{ actor.name }}
            </option>
          </select>
        </div>

        <!-- 一级分类选择 -->
        <div class="form-group">
          <label for="category" class="form-label">选择一级分类 *</label>
          <select
              id="category"
              v-model="formData.categoryId"
              @change="handleCategoryChange"
              class="form-select"
              required
          >
            <option value="">请选择一级分类</option>
            <option
                v-for="category in categories"
                :key="category.categoryId"
                :value="category.categoryId"
            >
              {{ category.name }}
            </option>
          </select>
        </div>

        <!-- 二级分类选择 -->
        <div class="form-group">
          <label for="subCategory" class="form-label">选择二级分类</label>
          <select
              id="subCategory"
              v-model="formData.subCategoryId"
              class="form-select"
              :disabled="!availableSubCategories.length"
          >
            <option value="">请选择二级分类</option>
            <option
                v-for="subCategory in availableSubCategories"
                :key="subCategory.subCategoryId"
                :value="subCategory.subCategoryId"
            >
              {{ subCategory.name }}
            </option>
          </select>
          <div v-if="formData.categoryId && !availableSubCategories.length" class="form-hint">
            该分类暂无二级分类
          </div>
        </div>

        <!-- 提交按钮 -->
        <div class="form-actions">
          <button
              type="submit"
              class="submit-btn"
              :disabled="isUploading || !videoFile"
          >
            <span v-if="isUploading">上传中...</span>
            <span v-else>上传视频</span>
          </button>
        </div>
      </form>

      <!-- 上传进度 -->
      <div v-if="isUploading" class="upload-progress">
        <div class="progress-bar">
          <div class="progress-fill" :style="{ width: uploadProgress + '%' }"></div>
        </div>
        <div class="progress-text">{{ uploadProgress }}%</div>
      </div>

      <!-- MD5计算进度 -->
      <div v-if="isCalculatingMd5" class="processing-status">
        <div class="processing-header">
          <div class="processing-text">正在计算文件MD5...</div>
          <div class="processing-spinner"></div>
        </div>
        <div class="progress-bar">
          <div class="progress-fill" :style="{ width: md5Progress + '%' }"></div>
        </div>
        <div class="progress-text">{{ md5Progress }}%</div>
      </div>

      <!-- 处理状态 -->
      <div v-if="isProcessing" class="processing-status">
        <div class="processing-header">
          <div class="processing-text">{{ processProgress.message || '正在处理视频...' }}</div>
          <div class="processing-spinner"></div>
        </div>
        <div class="progress-bar">
          <div class="progress-fill" :style="{ width: processProgress.progress + '%' }"></div>
        </div>
        <div class="progress-text">{{ processProgress.progress }}%</div>
      </div>

      <!-- 错误提示 -->
      <div v-if="errorMessage" class="error-message">
        {{ errorMessage }}
      </div>

      <!-- 成功提示 -->
      <div v-if="successMessage" class="success-message">
        {{ successMessage }}
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {ref, onMounted, onUnmounted, computed} from 'vue'
import {videoProcessor, type VideoInfo, type ProcessProgress} from '@/utils/videoProcessor'
import SparkMD5 from 'spark-md5'

// 类型定义
interface Actor {
  id: number
  name: string
}

interface SubCategory {
  subCategoryId: number
  name: string
  description: string
  coverImage: string | null
}

interface Category {
  categoryId: number
  name: string
  description: string
  coverImage: string | null
  subCategories: SubCategory[]
}

interface FormData {
  title: string
  description: string
  duration: number
  actorId: number | ''
  categoryId: number | ''
  subCategoryId: number | ''
}

// 常量
const API_BASE_URL = 'http://web.xiaowang.link:18001/api'
// const API_BASE_URL = 'http://localhost:8080/api'
const AUTH_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIsImNyZWF0ZVRpbWUiOjE3NDk5Njg2OTd9.5tMXRtOL5NYxOsSeeOiX8v2xPPtGAvDgAsGKrDKByN4'

// 响应式数据
const formData = ref<FormData>({
  title: '',
  description: '',
  duration: 0,
  actorId: '',
  categoryId: '',
  subCategoryId: ''
})

// 元素引用
const videoFileInput = ref<HTMLInputElement>()

// 文件和视频相关
const videoFile = ref<File | null>(null)
const videoInfo = ref<VideoInfo>({duration: 0, width: 0, height: 0, fps: 0, format: ''})
const extractedFrames = ref<string[]>([])
const selectedFrameIndex = ref<number>(0)
const processProgress = ref<ProcessProgress>({type: 'loading', progress: 0, message: ''})

// 数据和状态
const categories = ref<Category[]>([])
const actors = ref<Actor[]>([])
const isUploading = ref(false)
const isProcessing = ref(false)
const uploadProgress = ref(0)
const errorMessage = ref('')
const successMessage = ref('')
const processingMethod = ref<'ffmpeg' | 'html5'>('html5')

// 分片上传相关
const CHUNK_SIZE = 2 * 1024 * 1024 // 2MB per chunk
const fileMd5 = ref<string>('')
const totalChunks = ref(0)
const uploadedChunks = ref<Set<number>>(new Set())
const isCalculatingMd5 = ref(false)
const md5Progress = ref(0)

// 计算属性
const availableSubCategories = computed(() => {
  const selectedCategory = categories.value.find(cat => cat.categoryId === formData.value.categoryId)
  return selectedCategory ? selectedCategory.subCategories : []
})

// 方法
const triggerFileInput = () => {
  videoFileInput.value?.click()
}

const cleanupVideoResources = () => {
  // 清理提取的帧 URL
  extractedFrames.value.forEach(frameUrl => {
    URL.revokeObjectURL(frameUrl)
  })

  // 重置视频相关状态
  extractedFrames.value = []
  selectedFrameIndex.value = 0
  videoInfo.value = {duration: 0, width: 0, height: 0, fps: 0, format: ''}
  processProgress.value = {type: 'loading', progress: 0, message: ''}
}

// 计算文件MD5
const calculateFileMd5 = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const chunkSize = 2097152 // 2MB
    const chunks = Math.ceil(file.size / chunkSize)
    let currentChunk = 0
    const spark = new SparkMD5.ArrayBuffer()
    const fileReader = new FileReader()

    fileReader.onload = (e) => {
      spark.append(e.target?.result as ArrayBuffer)
      currentChunk++
      md5Progress.value = Math.round((currentChunk / chunks) * 100)

      if (currentChunk < chunks) {
        loadNext()
      } else {
        resolve(spark.end())
      }
    }

    fileReader.onerror = (e) => {
      reject(e)
    }

    function loadNext() {
      const start = currentChunk * chunkSize
      const end = Math.min(start + chunkSize, file.size)
      fileReader.readAsArrayBuffer(file.slice(start, end))
    }

    loadNext()
  })
}

// 检查分片状态
const checkChunkStatus = async (chunk: number): Promise<number> => {
  try {
    const response = await fetch(
      `${API_BASE_URL}/videos/check?fileMd5=${fileMd5.value}&chunk=${chunk}&fileName=${videoFile.value?.name}`,
      {
        headers: {
          'Authorization': `Bearer ${AUTH_TOKEN}`
        }
      }
    )
    const result = await response.json()
    return result.data
  } catch (error) {
    console.error('检查分片状态失败:', error)
    return 0
  }
}

// 上传分片
const uploadChunk = async (chunk: number, chunkBlob: Blob): Promise<boolean> => {
  try {
    console.log(`正在上传分片 ${chunk + 1}/${totalChunks.value}...`)
    const formData = new FormData()
    formData.append('file', chunkBlob)
    formData.append('fileMd5', fileMd5.value)
    formData.append('chunk', chunk.toString())
    formData.append('chunkSize', CHUNK_SIZE.toString())
    formData.append('totalChunks', totalChunks.value.toString())
    formData.append('fileName', videoFile.value?.name || '')

    const response = await fetch(`${API_BASE_URL}/videos/chunk`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${AUTH_TOKEN}`
      },
      body: formData
    })

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const result = await response.json()
    if (result.code === 200) {
      console.log(`分片 ${chunk + 1} 上传成功`)
      return true
    } else {
      throw new Error(result.message || '上传失败')
    }
  } catch (error) {
    console.error(`分片 ${chunk + 1} 上传失败:`, error)
    return false
  }
}

// 处理视频文件变更
const handleVideoFileChange = async (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files && target.files[0]) {
    // 清理之前的资源
    cleanupVideoResources()

    const file = target.files[0]
    videoFile.value = file

    // 自动生成标题（从文件名）
    const fileName = file.name.replace(/\.[^/.]+$/, "") // 移除扩展名
    formData.value.title = fileName.replace(/[_-]/g, ' ').trim()

    // 计算文件MD5
    isCalculatingMd5.value = true
    md5Progress.value = 0
    try {
      fileMd5.value = await calculateFileMd5(file)
      totalChunks.value = Math.ceil(file.size / CHUNK_SIZE)
      uploadedChunks.value.clear()
    } catch (error) {
      console.error('计算文件MD5失败:', error)
      errorMessage.value = '计算文件MD5失败，请重试'
      return
    } finally {
      isCalculatingMd5.value = false
    }

    // 设置 FFmpeg 进度回调
    videoProcessor.setProgressCallback((progress) => {
      processProgress.value = progress
    })

    // 开始处理视频
    isProcessing.value = true
    errorMessage.value = ''

    try {
      if (processingMethod.value === 'ffmpeg') {
        await processVideoWithFFmpeg(file)
      } else {
        await processVideoWithHTML5(file)
      }
    } catch (error) {
      console.error('视频处理失败:', error)
      errorMessage.value = `视频处理失败: ${error instanceof Error ? error.message : '未知错误'}`
      isProcessing.value = false
    }
  }
}

/**
 * 使用 FFmpeg 处理视频
 */
const processVideoWithFFmpeg = async (file: File): Promise<void> => {
  try {
    console.log('开始使用 FFmpeg 处理视频...')

    // 获取视频信息
    console.log('正在获取视频信息...')
    const info = await videoProcessor.getVideoInfo(file)

    // 更新视频信息
    videoInfo.value = info
    formData.value.duration = Math.round(info.duration)

    console.log('视频信息:', {
      时长: `${info.duration.toFixed(2)}秒`,
      分辨率: `${info.width}x${info.height}`,
      帧率: `${info.fps.toFixed(2)}fps`,
      格式: info.format
    })

    // 提取视频帧
    console.log('正在提取视频帧...')
    const frames = await videoProcessor.extractFrames(file, 5)

    extractedFrames.value = frames
    selectedFrameIndex.value = 0
    isProcessing.value = false

    console.log(`成功提取 ${frames.length} 帧`)
  } catch (error) {
    console.error('FFmpeg 视频处理失败:', error)
    console.log('尝试使用 HTML5 video 备用方案...')

    // 回退到 HTML5 video 处理
    try {
      await processVideoWithHTML5(file)
    } catch (fallbackError) {
      console.error('HTML5 video 备用方案也失败:', fallbackError)
      isProcessing.value = false
      throw new Error('视频处理失败，请尝试其他视频文件')
    }
  }
}

/**
 * HTML5 Video 备用处理方案
 */
const processVideoWithHTML5 = async (file: File): Promise<void> => {
  return new Promise((resolve, reject) => {
    console.log('使用 HTML5 video 处理视频...')
    processProgress.value = {type: 'processing', progress: 10, message: '使用备用方案处理视频...'}

    // 创建临时video元素
    const video = document.createElement('video')
    video.muted = true
    video.preload = 'metadata'

    const url = URL.createObjectURL(file)
    video.src = url

    let isCompleted = false

    const cleanup = () => {
      if (!isCompleted) {
        isCompleted = true
        URL.revokeObjectURL(url)
        video.remove()
      }
    }

    video.onloadedmetadata = async () => {
      try {
        const duration = Math.round(video.duration)
        const width = video.videoWidth
        const height = video.videoHeight

        // 更新视频信息（简化版）
        videoInfo.value = {
          duration,
          width,
          height,
          fps: 25, // 默认值
          format: 'video'
        }
        formData.value.duration = duration

        processProgress.value = {type: 'extracting', progress: 30, message: '正在提取视频帧...'}

        // 提取帧
        const frames = await extractFramesHTML5(video, 5)

        extractedFrames.value = frames
        selectedFrameIndex.value = 0
        isProcessing.value = false

        processProgress.value = {type: 'complete', progress: 100, message: '视频处理完成'}

        cleanup()
        resolve()
      } catch (error) {
        cleanup()
        reject(error)
      }
    }

    video.onerror = () => {
      cleanup()
      reject(new Error('视频加载失败'))
    }

    // 5分钟超时
    setTimeout(() => {
      if (!isCompleted) {
        cleanup()
        reject(new Error('视频处理超时'))
      }
    }, 300000)
  })
}

/**
 * HTML5 方式提取视频帧
 */
const extractFramesHTML5 = async (video: HTMLVideoElement, frameCount: number): Promise<string[]> => {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  if (!ctx) throw new Error('无法创建Canvas上下文')

  canvas.width = Math.min(video.videoWidth, 320)
  canvas.height = Math.min(video.videoHeight, 240)

  const frames: string[] = []
  const duration = video.duration

  for (let i = 0; i < frameCount; i++) {
    const time = (duration / (frameCount + 1)) * (i + 1)

    await new Promise<void>((resolve, reject) => {
      const seekHandler = () => {
        try {
          ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
          const frameData = canvas.toDataURL('image/jpeg', 0.8)
          frames.push(frameData)

          video.removeEventListener('seeked', seekHandler)

          processProgress.value = {
            type: 'extracting',
            progress: 30 + ((i + 1) / frameCount) * 60,
            message: `正在提取第 ${i + 1}/${frameCount} 帧...`
          }

          resolve()
        } catch (error) {
          video.removeEventListener('seeked', seekHandler)
          reject(error)
        }
      }

      const errorHandler = () => {
        video.removeEventListener('seeked', seekHandler)
        video.removeEventListener('error', errorHandler)
        reject(new Error('视频seek失败'))
      }

      video.addEventListener('seeked', seekHandler)
      video.addEventListener('error', errorHandler)
      video.currentTime = time

      // 10秒超时
      setTimeout(() => {
        video.removeEventListener('seeked', seekHandler)
        video.removeEventListener('error', errorHandler)
        reject(new Error('提取帧超时'))
      }, 10000)
    })
  }

  return frames
}

const selectFrame = (index: number) => {
  selectedFrameIndex.value = index
}

const handleCategoryChange = () => {
  formData.value.subCategoryId = ''
}

const fetchCategories = async () => {
  try {
    console.log('正在获取分类数据...')
    const response = await fetch(`${API_BASE_URL}/categories`, {
      headers: {
        'Authorization': `Bearer ${AUTH_TOKEN}`,
        'Content-Type': 'application/json'
      }
    })

    console.log('分类API响应状态:', response.status)

    if (!response.ok) {
      throw new Error(`获取分类失败: ${response.status}`)
    }

    const result = await response.json()
    console.log('分类API响应数据:', result)

    if (result.code === 200) {
      categories.value = result.data
      console.log('分类数据设置成功:', categories.value)
    } else {
      throw new Error(result.message || '获取分类失败')
    }
  } catch (error) {
    console.error('获取分类失败:', error)
    // 添加默认分类数据作为备用
    categories.value = [
      {
        categoryId: 1,
        name: '黑暗风',
        description: '黑暗风格类型',
        coverImage: null,
        subCategories: [
          {subCategoryId: 1, name: '心理惊悚', description: '心理惊悚子类型', coverImage: null},
          {subCategoryId: 2, name: '悬疑', description: '悬疑子类型', coverImage: null}
        ]
      },
      {
        categoryId: 2,
        name: '浪漫',
        description: '浪漫风格类型',
        coverImage: null,
        subCategories: [
          {subCategoryId: 3, name: '甜宠', description: '甜宠子类型', coverImage: null},
          {subCategoryId: 4, name: '虐恋', description: '虐恋子类型', coverImage: null}
        ]
      }
    ]
    errorMessage.value = `获取分类失败: ${error instanceof Error ? error.message : '未知错误'}，已加载默认分类`
  }
}

const fetchActors = async () => {
  try {
    console.log('正在获取演员数据...')
    const response = await fetch(`${API_BASE_URL}/categories/actors`, {
      headers: {
        'Authorization': `Bearer ${AUTH_TOKEN}`,
        'Content-Type': 'application/json'
      }
    })

    console.log('演员API响应状态:', response.status)

    if (!response.ok) {
      throw new Error(`获取演员列表失败: ${response.status}`)
    }

    const result = await response.json()
    console.log('演员API响应数据:', result)

    if (result.code === 200) {
      actors.value = result.data
      console.log('演员数据设置成功:', actors.value)
    } else {
      throw new Error(result.message || '获取演员列表失败')
    }
  } catch (error) {
    console.error('获取演员列表失败:', error)
    // 添加默认演员数据作为备用
    actors.value = [
      {id: 1, name: '张三'},
      {id: 2, name: '李四'},
      {id: 3, name: '王五'},
      {id: 4, name: '赵六'}
    ]
    const errorMsg = errorMessage.value ? errorMessage.value + ' | ' : ''
    errorMessage.value = errorMsg + `获取演员失败: ${error instanceof Error ? error.message : '未知错误'}，已加载默认演员`
  }
}

const dataURLtoBlob = (dataURL: string): Blob => {
  const arr = dataURL.split(',')
  const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/jpeg'
  const bstr = atob(arr[1])
  let n = bstr.length
  const u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new Blob([u8arr], {type: mime})
}

const handleSubmit = async () => {
  if (!videoFile.value) {
    errorMessage.value = '请选择视频文件'
    return
  }

  isUploading.value = true
  uploadProgress.value = 0
  errorMessage.value = ''
  successMessage.value = ''

  try {
    // 上传所有分片
    for (let chunk = 0; chunk < totalChunks.value; chunk++) {
      // 检查分片是否已上传
      const chunkStatus = await checkChunkStatus(chunk)
      if (chunkStatus === 1) {
        uploadedChunks.value.add(chunk)
        uploadProgress.value = Math.round((uploadedChunks.value.size / totalChunks.value) * 100)
        continue
      }

      // 计算当前分片的起始和结束位置
      const start = chunk * CHUNK_SIZE
      const end = Math.min(start + CHUNK_SIZE, videoFile.value.size)
      const chunkBlob = videoFile.value.slice(start, end)

      // 上传分片
      const success = await uploadChunk(chunk, chunkBlob)
      if (success) {
        uploadedChunks.value.add(chunk)
        uploadProgress.value = Math.round((uploadedChunks.value.size / totalChunks.value) * 100)
      } else {
        throw new Error(`分片 ${chunk + 1}/${totalChunks.value} 上传失败`)
      }
    }

    // 所有分片上传完成后，提交视频信息
    const formDataToSend = new FormData()

    // 添加选中的缩略图
    if (extractedFrames.value.length > 0) {
      const selectedFrameData = extractedFrames.value[selectedFrameIndex.value]
      const thumbnailBlob = dataURLtoBlob(selectedFrameData)
      formDataToSend.append('thumbnailFile', thumbnailBlob, 'thumbnail.jpg')
    }

    // 构建查询参数
    const params = new URLSearchParams({
      fileName: videoFile.value.name,
      fileMd5: fileMd5.value,
      title: formData.value.title,
      description: formData.value.description,
      duration: formData.value.duration.toString(),
      actorId: formData.value.actorId.toString(),
      categoryIds: formData.value.categoryId.toString(),
      ...(formData.value.subCategoryId && {subCategoryIds: formData.value.subCategoryId.toString()})
    })

    console.log('正在提交视频信息...')
    const response = await fetch(`${API_BASE_URL}/videos/upload?${params}`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${AUTH_TOKEN}`
      },
      body: formDataToSend
    })

    if (!response.ok) {
      throw new Error('上传失败')
    }

    const result = await response.json()
    if (result.code === 200) {
      successMessage.value = '视频上传成功！'
      resetForm()
    } else {
      throw new Error(result.message || '上传失败')
    }
  } catch (error) {
    console.error('上传失败:', error)
    errorMessage.value = `上传失败: ${error instanceof Error ? error.message : '未知错误'}`
  } finally {
    isUploading.value = false
    uploadProgress.value = 0
  }
}

const resetForm = () => {
  formData.value = {
    title: '',
    description: '',
    duration: 0,
    actorId: '',
    categoryId: '',
    subCategoryId: ''
  }
  videoFile.value = null

  // 清理视频资源
  cleanupVideoResources()

  if (videoFileInput.value) {
    videoFileInput.value.value = ''
  }
}

// 工具函数
const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const formatDuration = (seconds: number): string => {
  const hours = Math.floor(seconds / 3600)
  const minutes = Math.floor((seconds % 3600) / 60)
  const secs = seconds % 60

  if (hours > 0) {
    return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
  }
  return `${minutes}:${secs.toString().padStart(2, '0')}`
}

// 生命周期
onMounted(() => {
  fetchCategories()
  fetchActors()
})

onUnmounted(async () => {
  cleanupVideoResources()
  // 清理 FFmpeg 资源
  try {
    await videoProcessor.dispose()
  } catch (error) {
    console.warn('清理 FFmpeg 资源失败:', error)
  }
})
</script>

<style scoped>
.video-upload-container {
  width: 100%;
  margin: 0;
  padding: 2rem;
}

.upload-card {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  padding: 2.5rem;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.upload-title {
  text-align: center;
  color: #333;
  margin-bottom: 2rem;
  font-size: 2rem;
  font-weight: 700;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.upload-form {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.form-group {
  display: flex;
  flex-direction: column;
}

.form-label {
  font-weight: 600;
  color: #555;
  margin-bottom: 0.75rem;
  font-size: 1rem;
}

.file-upload-area {
  border: 3px dashed #ddd;
  border-radius: 12px;
  padding: 2rem;
  text-align: center;
  background: #fafafa;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.file-upload-area:hover {
  border-color: #667eea;
  background: #f0f4ff;
}

.file-upload-area.has-file {
  border-color: #22c55e;
  background: #f0fdf4;
}

.file-input-hidden {
  position: absolute;
  left: -9999px;
  opacity: 0;
}

.upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.upload-icon {
  font-size: 3rem;
  margin-bottom: 1rem;
}

.upload-text {
  font-size: 1.2rem;
  font-weight: 600;
  color: #333;
}

.upload-hint {
  color: #666;
  font-size: 0.9rem;
}

.file-info {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.file-icon {
  font-size: 2rem;
}

.file-details {
  text-align: left;
}

.file-name {
  font-weight: 600;
  color: #333;
  font-size: 1.1rem;
}

.file-size {
  color: #666;
  font-size: 0.9rem;
  margin-top: 0.25rem;
}

.file-info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.file-duration,
.file-resolution,
.file-fps,
.file-format {
  color: #666;
  font-size: 0.85rem;
  padding: 0.25rem 0.5rem;
  background: rgba(102, 126, 234, 0.1);
  border-radius: 4px;
  text-align: center;
}

.processing-method-selector {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-top: 0.5rem;
}

.method-option {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem;
  border: 2px solid #e5e7eb;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.3s ease;
  background: white;
}

.method-option:hover {
  border-color: #667eea;
  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
  transform: translateY(-2px);
}

.method-option.selected {
  border-color: #667eea;
  background: rgba(102, 126, 234, 0.05);
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.method-icon {
  font-size: 2rem;
  min-width: 2rem;
}

.method-info {
  flex: 1;
}

.method-name {
  font-weight: 600;
  color: #333;
  margin-bottom: 0.25rem;
}

.method-desc {
  font-size: 0.85rem;
  color: #666;
  line-height: 1.4;
}

.frames-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}

.frame-item {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.3s ease;
  border: 3px solid transparent;
}

.frame-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}

.frame-item.selected {
  border-color: #667eea;
  box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.3);
}

.frame-image {
  width: 100%;
  height: 120px;
  object-fit: cover;
  display: block;
}

.frame-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.frame-item:hover .frame-overlay,
.frame-item.selected .frame-overlay {
  opacity: 1;
}

.frame-number {
  color: white;
  font-weight: 600;
  font-size: 1.2rem;
}

.frame-hint {
  color: #666;
  font-size: 0.9rem;
  text-align: center;
}

.form-input,
.form-textarea,
.form-select {
  padding: 1rem;
  border: 2px solid #e5e7eb;
  border-radius: 10px;
  font-size: 1rem;
  transition: all 0.3s ease;
  background: white;
}

.form-input:focus,
.form-textarea:focus,
.form-select:focus {
  outline: none;
  border-color: #667eea;
  box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.form-input:read-only {
  background: #f9fafb;
  color: #6b7280;
}

.form-textarea {
  resize: vertical;
  min-height: 120px;
}

.form-hint {
  margin-top: 0.5rem;
  color: #6b7280;
  font-size: 0.85rem;
}

.form-actions {
  margin-top: 1rem;
}

.submit-btn {
  width: 100%;
  padding: 1.2rem;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  border-radius: 12px;
  font-size: 1.2rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.submit-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}

.submit-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none;
}

.upload-progress {
  margin-top: 1.5rem;
}

.progress-bar {
  width: 100%;
  height: 8px;
  background: #e5e7eb;
  border-radius: 4px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #667eea, #764ba2);
  transition: width 0.3s ease;
}

.progress-text {
  text-align: center;
  margin-top: 0.5rem;
  color: #666;
  font-weight: 600;
}

.processing-status {
  margin-top: 1.5rem;
  padding: 1.5rem;
  background: #f0f4ff;
  border-radius: 12px;
  border: 1px solid #e0e8ff;
}

.processing-header {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.processing-text {
  color: #667eea;
  font-weight: 600;
  font-size: 1rem;
}

.processing-spinner {
  width: 20px;
  height: 20px;
  border: 2px solid #e5e7eb;
  border-top: 2px solid #667eea;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.error-message {
  margin-top: 1.5rem;
  padding: 1rem;
  background: #fef2f2;
  color: #dc2626;
  border-radius: 8px;
  border: 1px solid #fecaca;
}

.success-message {
  margin-top: 1.5rem;
  padding: 1rem;
  background: #f0fdf4;
  color: #166534;
  border-radius: 8px;
  border: 1px solid #bbf7d0;
}

@media (max-width: 768px) {
  .video-upload-container {
    padding: 1rem;
  }

  .upload-card {
    padding: 1.5rem;
    border-radius: 15px;
    max-width: none;
    width: 100%;
  }

  .upload-title {
    font-size: 1.5rem;
  }

  .frames-container {
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  }

  .frame-image {
    height: 80px;
  }

  .form-input,
  .form-textarea,
  .form-select {
    padding: 0.75rem;
  }

  .upload-form {
    gap: 1.5rem;
  }
}
</style>
